/******************************************************************************
**
**                      (C)2023 Ninebot Limited
**
**                         All Right Reserved
**
** 1 tab == 4 spaces!
******************************************************************************/

#ifndef __CANFRAME_H__
#define __CANFRAME_H__

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* controller area network (CAN) kernel definitions */

/* special address description flags for the CAN_ID */
#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* error message frame */

/* valid bits in CAN ID for frame formats */
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */

/*
 * Controller Area Network Identifier structure
 *
 * bit 0-28	: CAN identifier (11/29 bit)
 * bit 29	: error message frame flag (0 = data frame, 1 = error message)
 * bit 30	: remote transmission request flag (1 = rtr frame)
 * bit 31	: frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
 */
typedef uint32_t canid_t;

#define CAN_SFF_ID_BITS 11
#define CAN_EFF_ID_BITS 29

/*
 * Controller Area Network Error Message Frame Mask structure
 *
 * bit 0-28	: error class mask (see include/linux/can/error.h)
 * bit 29-31	: set to zero
 */
typedef uint32_t can_err_mask_t;

/* CAN payload length and DLC definitions according to ISO 11898-1 */
#define CAN_MAX_DLC 8
#define CAN_MAX_DLEN 8

/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
#define CANFD_MAX_DLC 15
#define CANFD_MAX_DLEN 64

#ifdef CONFIG_CANBUS_CANFD
#define CAN_FRAME_MAX_DLC CANFD_MAX_DLC
#define CAN_FRAME_MAX_DLEN CANFD_MAX_DLEN
#else
#define CAN_FRAME_MAX_DLC CAN_MAX_DLC
#define CAN_FRAME_MAX_DLEN CAN_MAX_DLEN
#endif

/*
 * defined bits for canfd_frame.flags
 *
 * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
 * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
 * the CAN controllers bitstream processor into the CAN FD mode which creates
 * two new options within the CAN FD frame specification:
 *
 * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
 * Error State Indicator - represents the error state of the transmitting node
 *
 * As the CANFD_ESI bit is internally generated by the transmitting CAN
 * controller only the CANFD_BRS bit is relevant for real CAN controllers when
 * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
 * sense for virtual CAN interfaces to test applications with echoed frames.
 */
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
#define CANFD_FLAG 0x80000000U /* can fd frame flags */

/**
 * struct canfd_frame - CAN flexible data rate frame structure
 * @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
 * @len:    frame payload length in byte (0 .. CAN_FRAME_MAX_DLEN)
 * @flags:  additional flags for CAN FD
 * @__res0: reserved / padding
 * @__res1: reserved / padding
 * @data:   CAN (orFD) frame payload (up to CAN_FRAME_MAX_DLEN byte)
 */
struct can_frame {
	canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
	union {
		struct {
			uint8_t len; /* frame payload length in byte */
			uint8_t flags; /* additional flags for CAN FD */
			uint16_t sync_send_timeout; //sync send with timeout(tick), 0 means async
		};
		uint32_t misc;
	};
	union {
		void *send_task_handle;
		unsigned int recv_timestamp; //os tick, when receive
	};
	uint8_t data[CAN_FRAME_MAX_DLEN] /* __attribute__((aligned(8)))*/;
};

#define CAN_MTU (sizeof(struct can_frame))

#define CANFRAME_IS_CANFD(p) ((p)->flags & CANFD_FLAG)
#define CANFRAME_IS_XTD(p) ((p)->can_id & CAN_EFF_FLAG)
#define CANFRAME_IS_RTR(p) ((p)->can_id & CAN_RTR_FLAG)
#define CANFRAME_IS_BRS(p) ((p)->flags & CANFD_BRS)
#define CANFRAME_IS_ESI(p) ((p)->flags & CANFD_ESI)
#define CANFRAME_IS_ERR_FRAME(p) ((p)->flags & CAN_ERR_FLAG)
#define CANFRAME_ID(p) ((p)->can_id & ((1 << CAN_EFF_ID_BITS) - 1))

#define CANFRAME_SET_CANFD(p) ((p)->flags |= CANFD_FLAG)
#define CANFRAME_SET_XTD(p) ((p)->can_id |= CAN_EFF_FLAG)
#define CANFRAME_SET_RTR(p) ((p)->can_id |= CAN_RTR_FLAG)
#define CANFRAME_SET_BRS(p) ((p)->flags |= CANFD_BRS)
#define CANFRAME_SET_ESI(p) ((p)->flags |= CANFD_ESI)
#define CANFRAME_SET_ID(p, id)                \
	do {                                      \
		(p)->can_id &= ~CAN_EFF_MASK;         \
		(p)->can_id |= (CAN_EFF_MASK & (id)); \
	} while (0)

#define CANFRAME_INIT(p)              \
	do {                              \
		((p)->misc = 0);              \
		(p)->send_task_handle = NULL; \
	} while (0)

#ifdef __cplusplus
}
#endif

#endif
